#include "const.h"

static void writebuf_(const char *func, char *buf, size_t n, size_t i, char c) {
	if (i >= n)
		i_error__((const char *)0, 0, func, "overflow detected");

	buf[i] = c;
}
#define writebuf(buf,n,i,c) writebuf_(__func__, buf, n, i, c)

static size_t writestr_(const char *func, char *buf, size_t n, size_t i,
const char *src) {
	while(*src)
		writebuf_(func, buf, n, i++, *src++);
	return i;
}
#define writestr(buf,n,i,s) writestr_(__func__, buf, n, i, s)

const char *v_nformat(char *buf, size_t n, const char *format) {
	unsigned char format_char;
	const char *p, *end_p, *bracket_p, *bracket_e;
	char *t;
	size_t i, j, index;
	var_t v;
	char tmp[512], tmpindex[32];
	int isarray;

	i = 0;

	while(*format) {
		if (*format!='$') {
			writebuf(buf, n, i++, *format++);
			continue;
		}

		format++;
		switch(*format) {
		case '$':
			writebuf(buf, n, i++, '$');
			break;
		case '\"':
			writebuf(buf, n, i++, '\"');
			break;
		case '(':
			format++;

			tmp[0] = 0;

			if (!(p = strchr(format, ')'))) {
				writebuf(buf, n, i, 0);
				return buf;
			}

			bracket_p = strchr(format, '[');
			if (bracket_p > p)
				bracket_p = (const char *)0;

			end_p = bracket_p ? bracket_p : p;
			i_strncpy(tmp, sizeof(tmp), format, end_p-format);

			if (!tmp[0]) {
				format = &p[1];
				break;
			}

			if (bracket_p) {
				bracket_e = strchr(bracket_p, ']');
				if (bracket_e > p)
					bracket_e = (const char *)0;

				if (!bracket_e) {
					format = &p[1];
					break;
				}

				if (!(v = v_find(tmp))) {
					format = &p[1];
					break;
				}

				bracket_p++;
				i_strncpy(tmpindex, sizeof(tmpindex),
					bracket_p, bracket_e-bracket_p);
				index = (size_t)atoi(tmpindex);

				i = writestr(buf, n, i, v_get_array(v, index));
			} else {
				if ((t = strrchr(tmp, '.')) != (char *)0) {
					if (!strcmp(t, ".n")) {
						*t = 0;
						v = v_find(tmp);
						i = writestr(buf, n, i, v_array_expand_n(v));
					} else if(!strcmp(t, ".i")) {
						*t = 0;
						v = v_find(tmp);
						i = writestr(buf, n, i, v_array_expand_i(v));
					} else
						t = (char *)0;
				}

				if (!t) {
					v = v_find(tmp);
					i = writestr(buf, n, i, v_expand(v));
				}
			}

			format = &p[1];
			break;
		default:
			format_char = *(unsigned char *)format++;
			if (!(v = g_var_char[format_char])) {
				writebuf(buf, n, i, 0);
				return buf;
			}

			isarray = 0;
			if (*format=='[') {
				++format;
				tmpindex[0] = 0;
				for(j=0; j<sizeof(tmpindex)-1; j++) {
					if (*format==']')
						break;

					if (*format<'0' || *format>'9') {
						writebuf(buf, n, i, 0);
						return buf;
					}

					tmpindex[j] = *format++;
				}
				tmpindex[j] = 0;

				index = (unsigned int)atoi(tmpindex);
				isarray = 1;

				format++;
			}

			if (isarray)
				i = writestr(buf, n, i, v_get_array(v, index));
			else
				i = writestr(buf, n, i, v_expand(v));
			break;
		}
	}

	writebuf(buf, n, i, 0);
	return buf;
}
